import math
import typing
from enum import Enum

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
from PyQt5 import QtGui
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QOpenGLWidget


class EditMode(Enum):
    VIEW = 0
    MOVE = 1


EDIT_MODE_TO_NAME = {
    EditMode.VIEW: 'view',
    EditMode.MOVE: 'move',
}


class BasicGlWidget(QOpenGLWidget):
    textureLoaded = pyqtSignal(int, int)    # texture loaded, width, height

    def __init__(self, parent=None):
        super().__init__(parent)
        self._texture = None
        self.scale_factor = 0.9
        self.scale_cnt = 0
        self.camera_offset = (0.0, 0.0)
        self._gl_width = 200
        self._gl_height = 200

        # scale
        self.scale = 1.0

        # drag
        self._drag_flag = False
        self._drag_start = QPoint(0, 0)
        self.setMouseTracking(True)
        # edit move
        self._move_flag = False
        self._move_start = QPoint(0, 0)
        # parameters
        self._base_idx_list = [-1] * 3

    def resizeGL(self, w: int, h: int) -> None:
        self._gl_width = w
        self._gl_height = h
        glViewport(0, 0, w, h)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        _cox, _coy = self.camera_offset
        glOrtho(_cox, _cox + w * self.scale, _coy, _coy + h * self.scale, 0.01, 100.0)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        gluLookAt(0, 0, 5, 0, 0, 0, 0, 1, 0)

    def load_texture(self, file: str):
        im = Image.open(file)
        data = im.tobytes('raw', 'RGBA', 0, -1)
        glBindTexture(GL_TEXTURE_2D, self._texture)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, im.width, im.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
        glGenerateMipmap(GL_TEXTURE_2D)
        # 加载纹理完成时，发射信号
        self.textureLoaded.emit(im.width, im.height)

    def paintGL(self):
        pass

    def wheelEvent(self, a0: QtGui.QWheelEvent) -> None:
        super().wheelEvent(a0)
        # print(a0.angleDelta())
        if a0.angleDelta().y() == 0:
            return
        if a0.angleDelta().y() > 0:
            self.scale_cnt += 1
        else:
            self.scale_cnt -= 1
        self.scale = pow(self.scale_factor, self.scale_cnt)

        self.force_resize()

    def initializeGL(self):
        self._texture = glGenTextures(1)    # 需要在init创建纹理

    def draw_rect(self, color: tuple, x, y):
        """
        在目标位置绘制矩形，可视大小不受缩放影响
        :param color: 颜色
        :param x: x轴坐标中心
        :param y: y轴坐标中心
        :return:
        """
        _hv_size = 10 * self.scale
        glBegin(GL_LINE_LOOP)
        glColor3fv(color)
        glVertex3f(x - _hv_size, y - _hv_size, 0)
        glColor3fv(color)
        glVertex3f(x + _hv_size, y - _hv_size, 0)
        glColor3fv(color)
        glVertex3f(x + _hv_size, y + _hv_size, 0)
        glColor3fv(color)
        glVertex3f(x - _hv_size, y + _hv_size, 0)
        glEnd()

    def draw_diamond(self, color: tuple, x, y):
        """
        在目标位置绘制菱形，可视大小不受缩放影响
        :param color: 颜色
        :param x: x轴坐标中心
        :param y: y轴坐标中心
        :return:
        """
        _hv_size = 10 * self.scale
        glBegin(GL_LINE_LOOP)
        glColor3fv(color)
        glVertex3f(x, y - _hv_size, 0)
        glColor3fv(color)
        glVertex3f(x + _hv_size, y, 0)
        glColor3fv(color)
        glVertex3f(x, y + _hv_size, 0)
        glColor3fv(color)
        glVertex3f(x - _hv_size, y, 0)
        glEnd()

    def set_lock_base(self, idx, value):
        self._base_idx_list[min(idx, 2)] = value
        # print(self._base_idx_list)
        self.force_resize()

    def reset_lock_base(self):
        self._base_idx_list = [-1] * 3
        self.force_resize()

    def force_resize(self):
        pass


class UVGlWidget(BasicGlWidget):
    # focus mesh_idx, vertex_idx
    onFocus = pyqtSignal(int, int)       # focus a mesh with right mouse click
    onCurrentUVChanged = pyqtSignal(float, float)       # current focused uv. value between 0~1
    onMoveCurrent = pyqtSignal(float, float)            # edit move delta

    def __init__(self, parent=None):
        super().__init__(parent)

        self.canvas_size = (2048, 2048)     # 默认值2048

        # vertex
        self.moc3_vertex_cnt = []
        # uv
        self.moc3_uv_idx = []
        self.moc3_uv_xy = []
        # fragment
        self.moc3_drawable_start = []
        self.moc3_drawable_cnt = []
        self.moc3_drawable_index = []
        self.moc3_mesh_texture = []     # mesh序号 -> texture序号

        self._position2idx = {}         # 坐标 -> (mesh序号, vertex序号)
        self._texture_position2idx = {}     # 纹理序号 -> {坐标 -> (mesh序号, vertex序号)}

        self.show_outer_line = True

        # params
        self._highlight_idx = 0
        self._focus_only = False
        self._highlight_vertex = 0
        self._show_bg = False
        self._edit_mode = EditMode.VIEW
        self._texture_idx = -1      # 当前显示的纹理，-1表示显示所有纹理

    def set_highlight_idx(self, value: int):
        self._highlight_idx = value
        self._highlight_vertex = 0
        self.force_resize()

    def set_focus_only(self, value: bool):
        self._focus_only = value
        self.force_resize()

    def set_highlight_vertex(self, value: int):
        self._highlight_vertex = value
        self.force_resize()

    def set_show_bg(self, value: bool):
        self._show_bg = value
        self.force_resize()

    def set_edit_mode(self, mode: EditMode):
        self._edit_mode = mode

    def get_edit_mode(self) -> EditMode:
        return self._edit_mode

    def set_texture_idx(self, idx: int):
        self._texture_idx = idx
        self.force_resize()

    def refresh_indexes(self):
        # call this after data changed
        self._position2idx.clear()
        for i, vc in enumerate(self.moc3_vertex_cnt):
            uv_idx = self.moc3_uv_idx[i]
            for j in range(vc):
                _x = self.moc3_uv_xy[uv_idx + j * 2]
                _y = self.moc3_uv_xy[uv_idx + j * 2 + 1]
                self._position2idx[(_x, _y)] = (i, j)
        for k, v in self._position2idx.items():
            self._texture_position2idx.setdefault(self.moc3_mesh_texture[v[0]], {})[k] = v

    def set_canvas_size(self, width: int, height: int):
        self.canvas_size = (width, height)
        # # 延迟刷新，因为需要等待moc3_accessor更新数据
        # QtCore.QTimer.singleShot(100, lambda: [self.refresh_indexes(), self.force_resize()])
        self.refresh_indexes()
        self.force_resize()

    def initializeGL(self):
        super().initializeGL()

        glClearColor(0, 0, 0, 1)
        glEnable(GL_DEPTH_TEST)

        # self.load_texture('./chuixue_3/textures/texture_00.png')

    def paintGL(self):
        super().paintGL()

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        # background
        if self._show_bg:
            _w, _h = self.canvas_size
            glEnable(GL_BLEND)
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

            # self.gl_tex.bind()
            glBindTexture(GL_TEXTURE_2D, 1)
            glEnable(GL_TEXTURE_2D)
            glColor3f(1, 1, 1)
            glBegin(GL_QUADS)
            glTexCoord2f(0, 0)
            glVertex3f(0, 0, -0.1)
            glTexCoord2f(0, 1)
            glVertex3f(0, _h, -0.1)
            glTexCoord2f(1, 1)
            glVertex3f(_w, _h, -0.1)
            glTexCoord2f(1, 0)
            glVertex3f(_w, 0, -0.1)
            glEnd()
            glDisable(GL_TEXTURE_2D)

        # outer line
        if self.show_outer_line:
            glBegin(GL_LINE_LOOP)
            glColor3f(0.6, 0.6, 1.0)
            glVertex3f(0, 0, 0)
            glColor3f(0.6, 0.6, 1.0)
            glVertex3f(self.canvas_size[0], 0, 0)
            glColor3f(0.6, 0.6, 1.0)
            glVertex3f(self.canvas_size[0], self.canvas_size[1], 0)
            glColor3f(0.6, 0.6, 1.0)
            glVertex3f(0, self.canvas_size[1], 0)
            glEnd()

        # 可绘制区域，同样是Y轴反向。用于剔除不在可视区域的mesh
        draw_area_left_down = self.widget_pos_to_uv_pos(0, self._gl_height, invert_y=False)
        draw_area_left_down = (draw_area_left_down[0] * self.canvas_size[0], draw_area_left_down[1] * self.canvas_size[1])
        draw_area_right_up = self.widget_pos_to_uv_pos(self._gl_width, 0, invert_y=False)
        draw_area_right_up = (draw_area_right_up[0] * self.canvas_size[0], draw_area_right_up[1] * self.canvas_size[1])
        # print(draw_area_left_down, draw_area_right_up)
        # draw framed meshes
        for n, uv_idx, dr_start, dr_cnt, k in zip(
                self.moc3_vertex_cnt, self.moc3_uv_idx, self.moc3_drawable_start, self.moc3_drawable_cnt,
                range(len(self.moc3_vertex_cnt))):
            if self._texture_idx != -1 and self.moc3_mesh_texture[k] != self._texture_idx:
                continue
            if self._focus_only and self._highlight_idx != k:
                continue
            # highlight current
            _render_color = (0.4, 1.0, 0.4) if self._highlight_idx == k else (1.0, 1.0, 1.0)
            # calculate vertexes
            vertexes_x = []
            vertexes_y = []
            draw_fragments_flag = False
            for i in range(n):
                _x = self.moc3_uv_xy[uv_idx + i * 2]
                # _xt = (1.0 - _x) * self.canvas_size[0]
                _xt = _x * self.canvas_size[0]
                vertexes_x.append(_xt)     # OpenGL的坐标系与Live2D不同，它们的Y轴恰好相反
                _y = self.moc3_uv_xy[uv_idx + i * 2 + 1]
                _yt = (1.0 - _y) * self.canvas_size[1]
                vertexes_y.append(_yt)
                if self._highlight_idx == k:
                    if self._highlight_vertex == i:
                        # highlight vertex
                        self.onCurrentUVChanged.emit(_xt, _yt)
                        self.draw_rect((1.0, 0.4, 0.4), _xt, _yt)
                    if any(i == idx_base for idx_base in self._base_idx_list):
                        # highlight base vertex
                        self.draw_diamond((0.4, 0.4, 1.0), _xt, _yt)
                # 使用culling 减少一些渲染，以提高性能。首先转换坐标，然后判断vertex是否有顶点在矩形区域内，有则绘制。
                # 判断是否在可视区域内，draw_fragments_flag为True则绘制
                if draw_area_left_down[0] <= _xt <= draw_area_right_up[0] and \
                        draw_area_left_down[1] <= _yt <= draw_area_right_up[1]:
                    draw_fragments_flag = True
            if not draw_fragments_flag:
                continue
            # TODO 渲染不同texture index
            # draw fragments
            for i in range(0, dr_cnt, 3):
                _p1 = self.moc3_drawable_index[dr_start + i]
                _p2 = self.moc3_drawable_index[dr_start + i + 1]
                _p3 = self.moc3_drawable_index[dr_start + i + 2]
                # draw
                glBegin(GL_LINE_LOOP)
                glColor3fv(_render_color)
                glVertex3f(vertexes_x[_p1], vertexes_y[_p1], 0)
                glColor3fv(_render_color)
                glVertex3f(vertexes_x[_p2], vertexes_y[_p2], 0)
                glColor3fv(_render_color)
                glVertex3f(vertexes_x[_p3], vertexes_y[_p3], 0)
                glEnd()

    def force_resize(self):
        # 重绘，通过伪修改尺寸触发resizeGL（邪道）
        _s = self.size()
        self.resize(_s.width(), _s.height()+1)
        self.resize(_s)

    def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None:
        b = a0.button()
        if b == Qt.MouseButton.LeftButton and not a0.modifiers() & Qt.KeyboardModifier.ShiftModifier:
            # drag
            if self.geometry().contains(a0.pos() + self.pos()) and self._highlight_vertex not in self._base_idx_list:
                self._drag_start = a0.pos()
                self._drag_flag = True
        elif b == Qt.MouseButton.LeftButton and a0.modifiers() & Qt.KeyboardModifier.ShiftModifier:
            # move
            if self.geometry().contains(a0.pos() + self.pos()):
                self._move_start = a0.pos()
                self._move_flag = True
        elif b == Qt.MouseButton.RightButton:
            # focus on nearest mesh
            mouse_global_pos = a0.pos()
            _mx = mouse_global_pos.x()
            _my = mouse_global_pos.y()
            _mx, _my = self.widget_pos_to_uv_pos(_mx, _my)
            # find nearest point
            # print(_mx, _my)       # debug
            pos_current_texture = self._texture_position2idx.get(self._texture_idx, self._position2idx).items()
            if len(pos_current_texture) > 0:
                _, mini_idx = min(
                    pos_current_texture,
                    key=lambda kv: pow(_mx - kv[0][0], 2) + pow(_my - kv[0][1], 2)
                )
                self.onFocus.emit(mini_idx[0], mini_idx[1])

    def widget_pos_to_uv_pos(self, pos_x: int, pos_y: int, invert_y=True):
        _rx = pos_x / self.canvas_size[0] * self.scale
        _rx += self.camera_offset[0] / self.canvas_size[0]
        if invert_y:
            _ry = 1 - (self._gl_height - pos_y) / self.canvas_size[1] * self.scale
            _ry -= self.camera_offset[1] / self.canvas_size[1]
        else:
            _ry = (self._gl_height - pos_y) / self.canvas_size[1] * self.scale
            _ry += self.camera_offset[1] / self.canvas_size[1]
        return _rx, _ry

    def mouseReleaseEvent(self, a0: QtGui.QMouseEvent) -> None:
        b = a0.button()
        if b == Qt.MouseButton.LeftButton:
            self._drag_flag = False
            self._move_flag = False

    def mouseMoveEvent(self, a0: QtGui.QMouseEvent) -> None:
        if self._drag_flag:
            delta = a0.pos() - self._drag_start
            self._drag_start = a0.pos()
            self.camera_offset = (self.camera_offset[0] - delta.x() * self.scale,
                                  self.camera_offset[1] + delta.y() * self.scale)
            self.force_resize()
        elif self._move_flag:
            delta = a0.pos() - self._move_start
            self._move_start = a0.pos()
            _x = delta.x() * self.scale
            _y = -delta.y() * self.scale
            if _x != 0 or _y != 0:
                self.onMoveCurrent.emit(_x, _y)
            self.force_resize()


class VertexGlWidget(BasicGlWidget):
    onCurrentVertexChanged = pyqtSignal(float, float)       # current focused uv. value between 0~1
    onMoveCurrent = pyqtSignal(float, float)            # edit move delta
    onWheelSetVertex = pyqtSignal(int)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.canvas_size = (4800.0, 6180.0)
        self.canvas_origin = (2400.0, 3090.0)

        # vertex
        self.moc3_vertex_cnt = []
        # uv
        self.moc3_uv_idx = []
        self.moc3_uv_xy = []
        # fragment
        self.moc3_drawable_start = []
        self.moc3_drawable_cnt = []
        self.moc3_drawable_index = []
        # position
        self.moc3_kf_idx = []
        self.moc3_kf_cnt = []
        self.moc3_kf_idx2pos = []
        self.moc3_kf_data = []

        self.show_outer_line = True

        # vars
        self._last_paint_rect = [self.canvas_size[0], self.canvas_size[1]] * 2

        # params
        self._highlight_idx = 0
        self._roll_idx = 0
        self._highlight_vertex = 0
        self._show_bg = True
        self._edit_mode = EditMode.VIEW

    def set_highlight_idx(self, value: int):
        self._highlight_idx = value
        self._highlight_vertex = 0
        self._roll_idx = 0
        self.force_resize()

    def set_roll_idx(self, value: int):
        self._roll_idx = value
        self.force_resize()

    def set_highlight_vertex(self, value: int):
        self._highlight_vertex = value
        self.force_resize()

    def set_show_bg(self, value: bool):
        self._show_bg = value
        self.force_resize()

    def set_edit_mode(self, mode: EditMode):
        self._edit_mode = mode

    def get_edit_mode(self) -> EditMode:
        return self._edit_mode

    def set_canvas_rect(self, size: typing.Tuple[float, float], origin: typing.Tuple[float, float]):
        self.canvas_origin = origin
        self.canvas_size = size
        # self.force_resize()

    def initializeGL(self):
        super().initializeGL()

        glClearColor(0, 0, 0, 1)
        glEnable(GL_DEPTH_TEST)

        # self.load_texture('./chuixue_3/textures/texture_00.png')

    def paintGL(self):
        super().paintGL()

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        # outer line
        if self.show_outer_line:
            glBegin(GL_LINE_LOOP)
            glColor3f(0.6, 0.6, 1.0)
            glVertex3f(0, 0, 0)
            glColor3f(0.6, 0.6, 1.0)
            glVertex3f(self.canvas_size[0], 0, 0)
            glColor3f(0.6, 0.6, 1.0)
            glVertex3f(self.canvas_size[0], self.canvas_size[1], 0)
            glColor3f(0.6, 0.6, 1.0)
            glVertex3f(0, self.canvas_size[1], 0)
            glEnd()
        n = len(self.moc3_vertex_cnt)
        if n == 0:
            return
        _idx = min(self._highlight_idx, n - 1)
        _roll = min(self._roll_idx, self.moc3_kf_cnt[_idx] - 1)
        vertexes_x = []
        vertexes_y = []
        # x min, y min, x max, y max
        paint_rect = [self.canvas_origin[0], self.canvas_origin[1]] * 2
        _k = self.moc3_kf_idx2pos[self.moc3_kf_idx[_idx] + _roll]
        for i in range(self.moc3_vertex_cnt[_idx]):
            _x = self.moc3_kf_data[_k + i * 2] + self.canvas_origin[0]
            _y = -self.moc3_kf_data[_k + i * 2 + 1] + self.canvas_origin[1]
            vertexes_x.append(_x)
            vertexes_y.append(_y)
            # calc paint rect
            paint_rect[0] = min(paint_rect[0], _x)
            paint_rect[1] = min(paint_rect[1], _y)
            paint_rect[2] = max(paint_rect[2], _x)
            paint_rect[3] = max(paint_rect[3], _y)

            if self._highlight_vertex == i:
                # highlight vertex
                self.onCurrentVertexChanged.emit(_x, _y)
                self.draw_rect((1.0, 0.4, 0.4), _x, _y)
            if any(i == idx_base for idx_base in self._base_idx_list):
                self.draw_diamond((0.4, 0.4, 1.0), _x, _y)

        self._last_paint_rect = paint_rect
        # draw texture
        dr_start = self.moc3_drawable_start[_idx]
        if self._show_bg:
            _uvi = self.moc3_uv_idx[_idx]
            for i in range(0, self.moc3_drawable_cnt[_idx], 3):
                _p1 = self.moc3_drawable_index[dr_start + i]
                _p2 = self.moc3_drawable_index[dr_start + i + 1]
                _p3 = self.moc3_drawable_index[dr_start + i + 2]
                # draw
                glEnable(GL_BLEND)
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
                glBindTexture(GL_TEXTURE_2D, 1)
                glEnable(GL_TEXTURE_2D)

                glBegin(GL_TRIANGLES)
                glTexCoord2f(self.moc3_uv_xy[_uvi + _p1 * 2], 1.0 - self.moc3_uv_xy[_uvi + _p1 * 2 + 1])
                glColor3f(1.0, 1.0, 1.0)
                glVertex3f(vertexes_x[_p1], vertexes_y[_p1], -0.1)
                glTexCoord2f(self.moc3_uv_xy[_uvi + _p2 * 2], 1.0 - self.moc3_uv_xy[_uvi + _p2 * 2 + 1])
                glColor3f(1.0, 1.0, 1.0)
                glVertex3f(vertexes_x[_p2], vertexes_y[_p2], -0.1)
                glTexCoord2f(self.moc3_uv_xy[_uvi + _p3 * 2], 1.0 - self.moc3_uv_xy[_uvi + _p3 * 2 + 1])
                glColor3f(1.0, 1.0, 1.0)
                glVertex3f(vertexes_x[_p3], vertexes_y[_p3], -0.1)
                glEnd()

                glDisable(GL_TEXTURE_2D)

        # draw fragments
        for i in range(0, self.moc3_drawable_cnt[_idx], 3):
            _p1 = self.moc3_drawable_index[dr_start + i]
            _p2 = self.moc3_drawable_index[dr_start + i + 1]
            _p3 = self.moc3_drawable_index[dr_start + i + 2]
            # draw
            glBegin(GL_LINE_LOOP)
            glColor3f(1.0, 1.0, 1.0)
            glVertex3f(vertexes_x[_p1], vertexes_y[_p1], 0)
            glColor3f(1.0, 1.0, 1.0)
            glVertex3f(vertexes_x[_p2], vertexes_y[_p2], 0)
            glColor3f(1.0, 1.0, 1.0)
            glVertex3f(vertexes_x[_p3], vertexes_y[_p3], 0)
            glEnd()

    def force_resize(self):
        # 重绘，通过伪修改尺寸触发resizeGL（邪道）
        _s = self.size()
        self.resize(_s.width(), _s.height()+1)
        self.resize(_s)

    def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None:
        b = a0.button()
        if b == Qt.MouseButton.LeftButton and not a0.modifiers() & Qt.KeyboardModifier.ShiftModifier:
            if self.geometry().contains(a0.pos() + self.pos()) and self._highlight_vertex not in self._base_idx_list:
                self._drag_start = a0.pos()
                self._drag_flag = True
        elif b == Qt.MouseButton.LeftButton and a0.modifiers() & Qt.KeyboardModifier.ShiftModifier:
            # move
            if self.geometry().contains(a0.pos() + self.pos()):
                self._move_start = a0.pos()
                self._move_flag = True
        elif b == Qt.MouseButton.MidButton:
            _x0, _y0, _x1, _y1 = self._last_paint_rect
            _w = _x1 - _x0
            _h = _y1 - _y0
            if _w == 0 or _h == 0 or self._gl_width == 0 or self._gl_height == 0:
                print('bad parameter for scaling')
                return
            self.camera_offset = (_x0, _y0)
            scale_x = math.log(_w / self._gl_width, self.scale_factor)
            scale_y = math.log(_h / self._gl_height, self.scale_factor)
            self.scale_cnt = int(min(scale_y, scale_x))
            self.scale = pow(self.scale_factor, self.scale_cnt)

            self.force_resize()

    def mouseReleaseEvent(self, a0: QtGui.QMouseEvent) -> None:
        if a0.button() == Qt.MouseButton.LeftButton:
            self._drag_flag = False
            self._move_flag = False

    def mouseMoveEvent(self, a0: QtGui.QMouseEvent) -> None:
        if self._drag_flag:
            delta = a0.pos() - self._drag_start
            self.camera_offset = (self.camera_offset[0] - delta.x() * self.scale,
                                  self.camera_offset[1] + delta.y() * self.scale)
            self._drag_start = a0.pos()
            self.force_resize()
        elif self._move_flag:
            delta = a0.pos() - self._move_start
            self._move_start = a0.pos()
            _x = delta.x() * self.scale
            _y = -delta.y() * self.scale
            if _x != 0 or _y != 0:
                # print(_x, _y)
                self.onMoveCurrent.emit(_x, _y)
            self.force_resize()

    def wheelEvent(self, a0: QtGui.QWheelEvent) -> None:
        if a0.modifiers() & Qt.KeyboardModifier.ShiftModifier:
            # switch vertex
            self.onWheelSetVertex.emit(a0.angleDelta().y())
        else:
            super().wheelEvent(a0)
